package cn.com.eth.yx.ethpro.controller;//package cn.com.jdyun.controller;

import cn.com.eth.yx.ethpro.service.EthService;
import cn.com.eth.yx.ethpro.util.EthUtil;
import cn.com.eth.yx.ethpro.util.reponse.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.web3j.crypto.Bip39Wallet;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.admin.methods.response.PersonalUnlockAccount;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.DefaultBlockParameterNumber;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.core.methods.response.EthBlockNumber;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.utils.Convert;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

/**
 * @author admin
 */
@RestController
public class EthController {

    @Autowired
    private EthService ethService;

    /**
     * 创建eth钱包
     *
     * @param walletPwd
     * @return
     */
    @PostMapping("/eth/createWallet")
    public Result createEthWallet(String walletPwd) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        //通过密码及keystore目录生成钱包
        Bip39Wallet wallet;
        try {
            wallet = WalletUtils.generateBip39Wallet(walletPwd, new File(EthUtil.KEYSTOREPATH));
        } catch (Exception e) {
            throw new Exception("创建以太坊钱包失败");
        }
        //keyStore文件名
        String keyStoreKey = wallet.getFilename();
        resultMap.put("keyStoreKey", keyStoreKey);
        //12个单词的助记词
        resultMap.put("memorizingWords", wallet.getMnemonic());

        ///通过密码与助记词获得钱包地址、公钥及私钥信息
        Credentials credentials = WalletUtils.loadBip39Credentials(walletPwd,
                wallet.getMnemonic());
        //钱包地址
        System.out.println(credentials.getAddress());
        resultMap.put("walletAddr", credentials.getAddress());
        //公钥16进制字符串表示
        String publicKey = credentials.getEcKeyPair().getPublicKey().toString(16);
        resultMap.put("publicKey", publicKey);
        //私钥16进制字符串表示
        String privateKey = credentials.getEcKeyPair().getPrivateKey().toString(16);
        resultMap.put("privateKey", privateKey);
        Result r = new Result();
        r.setData(resultMap);
        return r;
    }

    /**
     * 查询钱包余额
     *
     * @param walletAddr
     * @return
     * @throws Exception
     */
    @PostMapping("/eth/getEthBalance")
    public Result getEthBalance(String walletAddr) throws Exception {

        Web3j web3j = EthUtil.getConnection();
        EthGetBalance ethGetBalance = null;
        try {
            // 通过账户地址查询余额
            ethGetBalance = web3j
                    .ethGetBalance("0xac91ff0261bc4b05dd0d5e23d9f80d24bf8079fe", DefaultBlockParameterName.LATEST)
                    .sendAsync()
                    .get();
        } catch (Exception e) {
            throw new Exception("查询钱包余额失败");
        }
        BigDecimal banlance = Convert.fromWei(ethGetBalance.getBalance().toString(), Convert.Unit.ETHER);
        Result r = new Result();
        r.setData(banlance);
        return null;
    }

    /**
     * 通过钱包密码和助记词找回私钥公钥
     *
     * @param walletPwd       钱包密码
     * @param memorizingWords 助记词
     * @return
     * @throws Exception
     */
    @PostMapping("/eth/getEthKeys")
    public Result getEthKeys(String walletPwd, String memorizingWords) throws Exception {
        Map<String, String> resultMap = new HashMap<>();
        //通过密码与助记词获得钱包地址、公钥及私钥信息
        Credentials credentials = WalletUtils.loadBip39Credentials(walletPwd, memorizingWords);
        //公钥16进制字符串表示
        String publicKey = credentials.getEcKeyPair().getPublicKey().toString(16);
        resultMap.put("publicKey", publicKey);
        //私钥16进制字符串表示
        String privateKey = credentials.getEcKeyPair().getPrivateKey().toString(16);
        resultMap.put("privateKey", privateKey);
        Result r = new Result();
        r.setData(resultMap);
        return r;
    }

    /**
     * 获得当前区块高度
     *
     * @return 当前区块高度
     * @throws IOException
     */
    public BigInteger getCurrentBlockNumber() throws IOException {
        Web3j web3j = EthUtil.getConnection();
        Request<?, EthBlockNumber> request = web3j.ethBlockNumber();
        return request.send().getBlockNumber();
    }

    /**
     * 解锁账户，发送交易前需要对账户进行解锁
     *
     * @param address  地址
     * @param password 密码
     * @param duration 解锁有效时间，单位秒
     * @return
     * @throws IOException
     */
    @PostMapping("/eth/unlockAccount")
    public static Boolean unlockAccount(String address, String password, BigInteger duration) throws IOException {
        Admin admin = EthUtil.initAdmin();
        Request<?, PersonalUnlockAccount> request = admin.personalUnlockAccount(address, password, duration);
        PersonalUnlockAccount account = request.send();
        return account.accountUnlocked();
    }

    /**
     * 获得ethblock
     * 查询区块内容
     *
     * @param blockNumber 根据区块编号
     * @return
     * @throws IOException
     */
    @PostMapping("/eth/getBlockEthBlock")
    public static EthBlock getBlockEthBlock(Integer blockNumber) throws IOException {
        Web3j web3j = EthUtil.getConnection();

        DefaultBlockParameter defaultBlockParameter = new DefaultBlockParameterNumber(blockNumber);
        Request<?, EthBlock> request = web3j.ethGetBlockByNumber(defaultBlockParameter, true);
        EthBlock ethBlock = request.send();

        return ethBlock;
    }

    /**
     * 指定地址转ETH至合约地址i
     *
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "transferOneCoinToken", method = RequestMethod.POST)
    public Result transferOneCoinToken(String account, String contractAddr, String amount, String gasPrice, String gasLimit, String walletPwd) throws Exception {

        Result result = new Result();
        Web3j web3j = EthUtil.getConnection();
        String txHash = ethService.tranferToContractAddr(web3j, account, contractAddr, amount, gasPrice, gasLimit, walletPwd);
        if (StringUtils.isEmpty(txHash)) {
            throw new Exception("转账失败");
        }
        result.setData(txHash);
        return result;
    }

    /**
     * eth转账
     *
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "transferOneCoinToken", method = RequestMethod.POST)
    public Result tranferEth(String fromAddr, String toAddr, String amount, String gasPrice, String gasLimit, String walletPwd) throws Exception {
        Result r = new Result();
        Web3j web3j = EthUtil.getConnection();

        String txHash = ethService.tranferEth(web3j, fromAddr, toAddr, amount, gasPrice, gasLimit, walletPwd);
        if (StringUtils.isEmpty(txHash)) {
            throw new Exception("转账失败");
        }
        r.setData(txHash);
        return r;
    }


}
